import ObservableObject from "../observer/observable.object"
import oe from "../math/19674"
export default class DynamicNumber extends ObservableObject {
  _slowdown: boolean
  _initialSpeed: number
  _speed: number
  _acceleration: number
  _desiredAcceleration: number
  _jerk: number
  _maxSpeed: number
  _minSpeed: number
  _startValue: number
  _value: number
  _endValue: number
  _delay: number
  _active: any
  _isSlowingDown: any
  _onComplete: any
  constructor(e = 1, t = 0) {
    super(),
      (this._slowdown = !0),
      (this._initialSpeed = 0),
      (this._speed = 0),
      (this._acceleration = 1),
      (this._desiredAcceleration = 1),
      (this._jerk = 1),
      (this._maxSpeed = 1),
      (this._minSpeed = 0.05),
      (this._startValue = 0),
      (this._value = 0),
      (this._endValue = e),
      (this._delay = t)
  }
  get active() {
    return this._active
  }
  get currentValue() {
    return this._value
  }
  get endValue() {
    return this._endValue
  }
  get speed() {
    return this._speed
  }
  get isSlowingDown() {
    return this._isSlowingDown
  }
  get maxSpeed() {
    return this._maxSpeed
  }
  get acceleration() {
    return this._acceleration
  }
  getProgressPercent() {
    return (this._value - this._startValue) / (this._endValue - this._startValue)
  }
  onComplete(e) {
    return (this._onComplete = e), this
  }
  setStartValue(e) {
    return (this._startValue = e), this
  }
  setCurrentValue(e) {
    return (this._value = e), this
  }
  setEndValue(e) {
    return (this._endValue = e), this
  }
  setInitialSpeed(e) {
    return (this._initialSpeed = e), this
  }
  setMaxSpeed(e) {
    return (this._maxSpeed = e), this
  }
  setDesiredAcceleration(e) {
    return (this._desiredAcceleration = e), (this._jerk = 3 * Math.abs(this._desiredAcceleration - this._acceleration)), this
  }
  activate(e) {
    return (this._active = e), this
  }
  setAccel(e) {
    return (this._acceleration = Math.abs(e)), this
  }
  start() {
    ;(this._active = !0), (this._value = this._startValue), (this._speed = this._initialSpeed)
  }
  setSlowdown(e) {
    return (this._slowdown = e), this
  }
  tick(e) {
    if (!this._active || e <= 0) return
    if (this._delay > 0) return void (this._delay -= e)
    e > 33 && (e = 33)
    const t = 0.001 * e,
      i = this._value,
      n = this._speed * t,
      s = oe.r_(i, this.endValue, n),
      r = this._endValue - i <= this.getSlowdownDistance(),
      o = this._slowdown && r,
      a = o ? this._minSpeed : this._maxSpeed,
      l = this.acceleration * t
    ;(this._speed = oe.r_(this._speed, a, l)), (this._isSlowingDown = o)
    const c = this._desiredAcceleration,
      h = this._jerk * t
    return (
      (this._acceleration = oe.r_(this._acceleration, c, h)),
      (this._value = s),
      this.commit(),
      s === this.endValue ? (this.activate(!1), void (this._onComplete && this._onComplete())) : void 0
    )
  }
  getSlowdownDistance() {
    const e = this.speed,
      t = this._acceleration,
      i = e / (0 === t ? 1e-5 : t)
    return this.speed * i + 0.5 * t * i * i
  }
  stop(e) {
    ;(this._active = !1), (this._endValue = e), this.commit()
  }
}
